/*
 *  Copyright (c) 2022 ZhuHai Jieli Technology Co.,Ltd.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

// *********************************************************************************//
//  Module name : HWI                                                               //
//  Description : hardware interrupt subroutine                                     //
//  By Designer : ZeQuan_liu                                                        //
//  Dat changed :                                                                   //
// *********************************************************************************//

#include "hwi.h"
#include "typedef.h"
#include "csfr.h"

extern int ISR_BASE;
#define ISR_ENTRY  ((u32)&ISR_BASE)

volatile int cpu_lock_cnt[CPU_CORE_NUM] = {0};
volatile int irq_lock_cnt[CPU_CORE_NUM] = {0};

u8 __attribute__((weak))irq_priority_get(u8 index)
{
    return 0xff;
}

void request_irq(u8 index, u8 priority, void (*handler)(void), u8 cpu_id)
{
    unsigned char icfg_wdat;
    unsigned int icfg_num, icfg_bit;
    unsigned int *israddr = (unsigned int *)ISR_ENTRY;

    u8 priority_tmp = irq_priority_get(index);
    if (priority_tmp == 0xff) {
        priority_tmp = priority;
    }

    israddr[index] = (u32)handler;

    icfg_num =  index / 8;
    icfg_bit = (index % 8) * 4;
    icfg_wdat = ((priority_tmp & 0x7) << 1) | BIT(0);
    unsigned int icfg_clr = ~(0xf << icfg_bit);
    unsigned int icfg_set = icfg_wdat << icfg_bit;

    local_irq_disable();

    volatile unsigned int *icfg_ptr = &(q32DSP(0)->ICFG00);
    icfg_ptr[icfg_num] = (icfg_ptr[icfg_num] & icfg_clr) | icfg_set;

    local_irq_enable();
}

void interrupt_init(void)
{
    int i ;

    local_irq_disable();

    volatile unsigned int *icfg_ptr = &(q32DSP(0)->ICFG00);
    for (i = 0 ; i < 32 ; i++) {
        icfg_ptr[i] = 0;
    }

    local_irq_enable();
}

// interrupt ip
void reg_set_ip(unsigned char index, unsigned char priority)
{
    unsigned char icfg_wdat;
    unsigned int icfg_num, icfg_bit;

    icfg_num =  index / 8;
    icfg_bit = (index % 8) * 4;
    icfg_wdat = (priority & 0x7) << 1;
    unsigned int icfg_clr = ~(0xe << icfg_bit);
    unsigned int icfg_set = icfg_wdat << icfg_bit;

    local_irq_disable();

    volatile unsigned int *icfg_ptr = &(q32DSP(0)->ICFG00);
    icfg_ptr[icfg_num] = (icfg_ptr[icfg_num] & icfg_clr) | icfg_set;

    local_irq_enable();
}

// interrupt ie
void bit_set_ie(unsigned char index)
{
    unsigned int icfg_num, icfg_bit;

    icfg_num =  index / 8;
    icfg_bit = (index % 8) * 4;

    local_irq_disable();

    volatile unsigned int *icfg_ptr = &(q32DSP(0)->ICFG00);
    icfg_ptr[icfg_num] |= BIT(icfg_bit);

    local_irq_enable();
}

void bit_clr_ie(unsigned char index)
{
    unsigned int icfg_num, icfg_bit;

    icfg_num =  index / 8;
    icfg_bit = (index % 8) * 4;

    local_irq_disable();
    volatile unsigned int *icfg_ptr = &(q32DSP(0)->ICFG00);
    icfg_ptr[icfg_num] &= ~BIT(icfg_bit);
    local_irq_enable();
}

void hwi_all_close(void)
{
    int i ;
    for (i = 0; i < 64; i++) {
        bit_clr_ie(i);
    }
}

BOOL irq_read(u32 index)
{
    unsigned int icfg_num =  index / 8;
    unsigned int icfg_bit = (index % 8) * 4;

    volatile unsigned int *icfg_ptr = &(q32DSP(0)->ICFG00);
    return (icfg_ptr[icfg_num] & BIT(icfg_bit)) ? 1 : 0;
}

void sfc_set_unenc_addr_range(u32 low_addr, u32 high_addr)
{
}

void unrequest_irq(u8 index)
{
    bit_clr_ie(index);
}

#ifdef IRQ_TIME_COUNT_EN

#include "printf.h"
static u32 irq_enter_time[80] = {0};
static u32 irq_enter_timestamp[80] = {0};

void irq_handler_enter(int irq)
{
    if (!(T2_CON & BIT(0))) {
        T2_CNT = 0;
        T2_PRD = 120000000 / 10;
        T2_CON = 1;
    }
    irq_enter_timestamp[irq] = T2_CNT;
}

void irq_handler_exit(int irq)
{
    u32 t = T2_CNT;
    if (t > irq_enter_timestamp[irq]) {
        t -= irq_enter_timestamp[irq];
    } else {
        t += T2_PRD - irq_enter_timestamp[irq];
    }

    irq_enter_time[irq] += t;
}

void irq_handler_times_dump()
{
    int i;
    u32 total = 0;

    for (i = 0; i < ARRAY_SIZE(irq_enter_time); i++) {
        if (irq_enter_time[i]) {
            total += irq_enter_time[i];
            irq_enter_time[i] = 0;
        }
    }
}
#endif
